use std::collections::HashMap;
use std::fmt::Display;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum PartKind {
    Extremely,
    Musical,
    Aerodynamic,
    Shiny,
}

#[derive(Debug, PartialEq)]
pub struct Rating {
    parts: HashMap<PartKind, i32>,
}

impl Rating {
    pub fn new(parts: HashMap<PartKind, i32>) -> Self {
        Self {
            parts
        }
    }

    pub fn part(&self, kind: PartKind) -> i32 {
        self.parts.get(&kind).unwrap().clone()
    }
}

impl Display for Rating {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, 
            "{{x={},m={},a={},s={}}}", 
            self.part(PartKind::Extremely),
            self.part(PartKind::Musical),
            self.part(PartKind::Aerodynamic),
            self.part(PartKind::Shiny)
        )?;
        Ok(())
    }
}

impl From<&str> for Rating {
    fn from(value: &str) -> Self {
        // {x=787,m=2655,a=1222,s=2876}
        let value = &value[1..value.len()-1];
        Self {
            parts: value.split(",").map(|part_str|{
                let equal_pos = part_str.find('=').expect("Error rating string.");
                let kind: PartKind = match &part_str[..equal_pos] {
                    "x" => PartKind::Extremely,
                    "m" => PartKind::Musical,
                    "a" => PartKind::Aerodynamic,
                    "s" => PartKind::Shiny,
                    _ => panic!("Error part type")
                };
                let value: i32 = part_str[equal_pos+1..].parse().expect("Error part value string.");
                (kind, value)
            }).collect()
        }
    }
}